
package com.zed.api.common;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import reactor.core.publisher.Mono;

/**
 * 支持{@link ApplicationContextAwareExtend} 和 {@link ApplicationContextAware}的抽象类
 *
 * @author Zed
 */
public abstract class ApplicationContextSupport implements ApplicationContextAwareExtend, ApplicationEventPublisherAware {

    private transient ApplicationContext context;
    protected transient ApplicationEventPublisher eventPublisher;

    /**
     *
     */
    public ApplicationContextSupport() {

    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {
        if (this.eventPublisher == null) {
            this.eventPublisher = eventPublisher;
            this.bindApplicationEventPublisher(eventPublisher);
        }
    }

    /**
     * 绑定应用事件发布者,当为null时绑定才触发
     *
     * @param eventPublisher {@link ApplicationEventPublisher}
     */
    protected void bindApplicationEventPublisher(ApplicationEventPublisher eventPublisher) {

    }

    @Override
    public void setApplicationContext(ApplicationContext context) {
        if (this.context == null) {
            this.context = context;
            this.bindApplicationContext(this.context);
        }
    }

    /**
     * 绑定应用上下文
     *
     * @param context {@link ApplicationContext}
     */
    protected void bindApplicationContext(ApplicationContext context) {

    }

    /**
     * 发布{@code event}事件
     *
     * @param event {@link Object}
     */
    protected void publishEvent(Object event) {
        this.eventPublisher.publishEvent(event);
    }

    /**
     * 异步发布事件
     */
    private void asyncPublishEvent() {
        //TODO 后续完善,目前修饰为private不让调用
    }


    /**
     * 获取上下文
     *
     * @return {@link ApplicationContext}
     */
    protected ApplicationContext getContext() {
        return this.context;
    }


    /**
     * 获取实例,如果不存在则会抛出例外 {@link BeansException}
     *
     * @param clazz {@link Class}
     * @return {@link B}
     */
    protected <B> B getBean(Class<B> clazz) {
        return this.context.getBean(clazz);
    }

    /**
     * 以响应式编程获取实例,存在例外时使用{@code Mono#error}
     *
     * @param clazz {@link Class}
     * @return {@link Mono}
     */
    protected <B> Mono<B> getBeanWithMono(Class<B> clazz) {
        try {
            return Mono.just(this.getBean(clazz));
        } catch (Exception e) {
            return Mono.error(e);
        }
    }

    /**
     * 查询Bean
     *
     * @param clazz {@link Class},查询类型
     * @return {@link B},可能为null
     */
    protected <B> B findBean(Class<B> clazz) {
        try {
            return this.getBean(clazz);
        } catch (Exception e) {
            return null;
        }
    }

}
